﻿using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using Mrkz.ImageManipulation;
using Mrkz.ImageManipulation.FrequencyFiltering;
using Mrkz.ImageManipulation.SpatialFiltering;
using System.IO;


namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {       
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            ReloadPicture();
        }

        #region commands
        private void cmdLoad_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog of = new Microsoft.Win32.OpenFileDialog();
            of.Filter = "Images|*.jpg;*.png;*.bmp";
            of.Multiselect = false;
            of.CheckFileExists = true;
            of.CheckPathExists = true;
            
            Nullable<bool> b = of.ShowDialog();

            if (b.HasValue && b.Value)
            {
                Properties.Settings.Default.LastFileName =  of.FileName;
                Properties.Settings.Default.Save();
                ReloadPicture();
            }
        }
        
        private void cmdSave_Click(object sender, RoutedEventArgs e)
        {
            if (imagedst.Source == null)
                return;

            Microsoft.Win32.SaveFileDialog of = new Microsoft.Win32.SaveFileDialog();
            of.Filter = "Images|*.jpg;*.png;*.bmp";            
            of.CheckFileExists = false;
            of.CheckPathExists = true;

            Nullable<bool> b = of.ShowDialog();

            if (b.HasValue && b.Value)
            {
                using (FileStream stream = new FileStream(of.FileName, FileMode.Create))
                {
                    var encoder = new JpegBitmapEncoder();
                    encoder.QualityLevel = 100;
                    encoder.Frames.Add(BitmapFrame.Create(imagedst.Source as BitmapSource));
                    encoder.Save(stream);
                }
            }
        }      

        private void ReloadPicture()
        {
            if (Properties.Settings.Default.LastFileName.Trim() == "")
                return;

            BitmapImage b = new BitmapImage(new Uri(Properties.Settings.Default.LastFileName));
            imagesrc.Source = b;

        }

        private void cmdSwap_Click(object sender, RoutedEventArgs e)
        {
            imagesrc.Source = imagedst.Source;
            imagedst.Source = null;
        }
        #endregion

        private void cmdTestFilter_Click(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
            st.Start();
            {
                Mrkz.ImageManipulation.TImage<Pixel> i = ImageFactory<Pixel>.FromBitmapSource(imagesrc.Source as BitmapSource);

                SpatialFilterKernel KR = new IdentityFilterKernel(5);
                SpatialFilterKernel KG = new IdentityFilterKernel(5);
                SpatialFilterKernel KB = new IdentityFilterKernel(5);

                ParametricFilterKernelBase vignette = new PowVignetteFilter(0.7f);              

                SpatialFilterEngine<Pixel> Filter =
                    new SpatialFilterEngine<Pixel>(KR,KB,KG, vignette);

                Mrkz.ImageManipulation.TImage<Pixel> ioutput = Filter.ParallelCalculateFilter(i);
                
                SpatialFilterKernel K2 = new MotionBlur5();
                MaskFilterBase mask = new LinearVignetteMask();
                SpatialFilterEngine<Pixel> e2 = new SpatialFilterEngine<Pixel>(K2, K2, K2, null, mask);
                ioutput = e2.ParallelCalculateFilter(ioutput);
                
                WriteableBitmap wb = new WriteableBitmap(imagesrc.Source as BitmapSource);
                InteropImage<Pixel>.WritePixels(ioutput, wb);

                imagedst.Source = wb;
            }
            st.Stop();
            TimeSpan t = st.Elapsed;
            txtElapsed.Content = t.TotalMilliseconds.ToString("N1");
           
        }

        private async Task<TImage<ComplexPixel>> ForwardTransformAsync(Mrkz.ImageManipulation.TImage<Pixel> i)
        {
            ILFFTEngine engine = new ILFFTEngine();
            return  await Task.Run<Mrkz.ImageManipulation.TImage<ComplexPixel>>(() => (engine.ForwardTransform(i)));
        }

        private async Task<TImage<Pixel>> InverseTransformAsync(Mrkz.ImageManipulation.TImage<ComplexPixel> i)
        {
            ILFFTEngine engine = new ILFFTEngine();
            return await Task.Run<Mrkz.ImageManipulation.TImage<Pixel>>(() => (engine.InverseTransform(i)));          
        }    

        #region filters

        private async void cmdLowPass_Click(object sender, RoutedEventArgs e)
        {
            lblrun.Visibility = System.Windows.Visibility.Visible;
            float f = (float)SlideIntensity.Value;

            Mrkz.ImageManipulation.TImage<Pixel> i = ImageFactory<Pixel>.FromBitmapSource(imagesrc.Source as BitmapSource);

            Mrkz.ImageManipulation.TImage<Pixel> rfinal =
                                await filterchains.Async_o_matic(() =>
                                {
                                    return filterchains.LowPass(i, f);
                                });

            WriteDest(rfinal);

            lblrun.Visibility = System.Windows.Visibility.Hidden;
        }

        private async void cmdHighPass_Click(object sender, RoutedEventArgs e)
        {
            lblrun.Visibility = System.Windows.Visibility.Visible;
            float f = (float)SlideIntensity.Value;

            Mrkz.ImageManipulation.TImage<Pixel> i = ImageFactory<Pixel>.FromBitmapSource(imagesrc.Source as BitmapSource);

            Mrkz.ImageManipulation.TImage<Pixel> rfinal = 
                                await filterchains.Async_o_matic(() =>
                                {
                                    return filterchains.HighPass(i, f);
                                });

            WriteDest(rfinal);           

            lblrun.Visibility = System.Windows.Visibility.Hidden;
        }

        private async void cmdIncBrightness_Click(object sender, RoutedEventArgs e)
        {
            lblrun.Visibility = System.Windows.Visibility.Visible;
            float f = (float)SlideIntensity.Value;

            Mrkz.ImageManipulation.TImage<Pixel> i = ImageFactory<Pixel>.FromBitmapSource(imagesrc.Source as BitmapSource);

            Mrkz.ImageManipulation.TImage<Pixel> rfinal =
                                await filterchains.Async_o_matic(() =>
                                {
                                    return filterchains.IncreaseBrightness(i, f);
                                });

            WriteDest(rfinal);

            lblrun.Visibility = System.Windows.Visibility.Hidden;
        }

        #endregion

        private void WriteDest(TImage<Pixel> rfinal)
        {
            WriteableBitmap res = new WriteableBitmap(imagesrc.Source as BitmapSource);
            InteropImage<Pixel>.WritePixels(rfinal, res);
            imagedst.Source = res;   
        }               
       
    }


    public static class filterchains
    {
        public static async Task<TImage<Pixel>> Async_o_matic(Func<TImage<Pixel>> ftask)
        {
            return await Task.Run<TImage<Pixel>>(ftask);
        }

        public static TImage<Pixel> LowPass(TImage<Pixel> inputimage,float effectintensity)
        {
            ILFFTEngine engine = new ILFFTEngine();

            TImage<ComplexPixel> i1 = engine.ForwardTransform(inputimage);

            ParametricFilterKernelBase vignette = new InversePowVignetteFilter(effectintensity);
            SpatialFilterEngine<ComplexPixel> se = new SpatialFilterEngine<ComplexPixel>(new IdentityFilterKernel(1), vignette);
            TImage<ComplexPixel> i2 = se.ParallelCalculateFilter(i1);

            TImage<Pixel> o = engine.InverseTransform(i2);
            return o;
        }

        public static TImage<Pixel> HighPass(TImage<Pixel> inputimage,float effectintensity)
        {
            ILFFTEngine engine = new ILFFTEngine();

            TImage<ComplexPixel> i1 = engine.ForwardTransform(inputimage);

            ParametricFilterKernelBase vignette = new PowVignetteFilter(effectintensity);
            SpatialFilterEngine<ComplexPixel> se = new SpatialFilterEngine<ComplexPixel>(new IdentityFilterKernel(1), vignette);
            TImage<ComplexPixel> i2 = se.ParallelCalculateFilter(i1);

            TImage<Pixel> o = engine.InverseTransform(i2);
            return o;
        }

        public static TImage<Pixel> IncreaseBrightness(TImage<Pixel> inputimage, float effectintensity)
        {
            SpatialFilterKernel kernel = new IdentityFilterKernel(1);
            kernel = kernel.AdjustEffectIntensity(effectintensity);
            SpatialFilterEngine<Pixel> e2 = new SpatialFilterEngine<Pixel>(kernel);

            Mrkz.ImageManipulation.TImage<Pixel> o = e2.ParallelCalculateFilter(inputimage);
            return o;
        }
    }
}
